#include "base/log.h"

#include <bits/stl_algo.h>
#include <memory.h>
#include <sys/time.h>
#include <time.h>

#include "base/logstream.h"
namespace net_tools::base{
namespace detail{
const char digitsHex[] = "0123456789ABCDEF";
const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
template<typename T>
short int Convert(char buf[], T value){
  T i = value;
  char* p = buf;
  do{
    int lsd = static_cast<int>(i % 10);
    i /= 10;
    *p++ = zero[lsd];
  } while (i != 0);
  if (value < 0)
  {
    *p++ = '-';
  }
  *p = ' ';
  std::reverse(buf, p);
  return p - buf;
};
short int ConvertHex(char buf[],uint64_t value){
  uint64_t i = value;
  char* p = buf;
  do
  {
    int lsd = static_cast<int>(i % 16);
    i /= 16;
    *p++ = digitsHex[lsd];
  } while (i != 0);

  *p = ' ';
  std::reverse(buf, p);
  return p - buf;
};
} // namespace detail
Logstream::Logstream(unsigned int tid)
  :base_len_(5+10+7+6+6),
   buffer_len_(0),
   is_out_buffer_(false)
{
  timeval val;
  gettimeofday(&val,NULL);
  last_time_ = val.tv_sec;
  struct tm tm_time_;
  localtime_r(&val.tv_sec,&tm_time_);
  min_ = tm_time_.tm_min;
  sec_ = tm_time_.tm_sec;
  strftime((reinterpret_cast<char*>(this)),15,"%m_%d-%H:%M:%S",&tm_time_);

  detail::Convert(utime_-1,val.tv_usec+1000000);
  time_[9] = '.';
  memset(tid_,' ',7);
  detail::Convert(tid_+1,tid);
  tid_[6] = ' ';
};
Logstream::~Logstream(){};
Logstream& Logstream::Init(const char* file,int len,Log_level level){
  memcpy(log_level_,LogLevelName[level],6);
  file_ = const_cast<char*>(file);
  len_ = len;
  timeval tm;
  gettimeofday(&tm,NULL);
  detail::Convert(utime_-1,tm.tv_usec+1000000);
  __time_t diff = tm.tv_sec - last_time_;
  if(diff){
    last_time_ = tm.tv_sec;
    sec_ += diff;
    if(sec_ >= 60) [[unlikely]] {
      int add = sec_/60;
      min_ += add;
      sec_ = sec_%60;
      if(add) [[unlikely]] {
        struct tm tm_time_;
        localtime_r(&tm.tv_sec,&tm_time_);
        strftime((reinterpret_cast<char*>(this)),15,"%m_%d-%H:%M:%S",&tm_time_);
      }else{
        detail::Convert(time_+3,min_ + 100);
        time_[3] = ':';
        detail::Convert(time_+6,sec_ + 100);
        time_[6] = ':';
      }
    }else{
      detail::Convert(time_+6,sec_ + 100);
      time_[6] = ':';
    }
  }
  time_[9] = '.';
  tid_[0] = ' ';
  return *this;
};
void Logstream::Append(const char* address,short int len){
  Is_out_buffer(len);
  memcpy(data_buffer+buffer_len_,address,len);
  buffer_len_ += len;
};
void Logstream::Is_out_buffer(short int len){
  if(buffer_len_+len > _C::SET_LOG_ONE_LOG_MAX_SIZE) [[unlikely]] { //需要刷入
    if(is_out_buffer_){ //已经越界一次
      Log::output_((reinterpret_cast<char*>(this))+base_len_,buffer_len_);
      buffer_len_ = 0;
    }else{ //需要打印头
      Log::output_(this,base_len_ + buffer_len_);
      buffer_len_ = 0;
      is_out_buffer_ = true;
    }
  }
};
template<typename T>
void Logstream::Format_integer(T v){
  Is_out_buffer(_C::SET_LOG_FMT_MAX_LEN);
  buffer_len_ += detail::Convert(data_buffer + buffer_len_,v);
};

Logstream& Logstream::operator<<(Logendl* end){
  data_buffer[buffer_len_] = ' ';
  data_buffer[buffer_len_+1] = ' ';
  buffer_len_ += 2;
  int file_len = strlen(file_);
  memcpy(data_buffer+buffer_len_,file_,file_len);
  buffer_len_ += file_len;
  data_buffer[buffer_len_] = ':';
  buffer_len_ += 1;
  buffer_len_ += detail::Convert(data_buffer+buffer_len_,len_);
  data_buffer[buffer_len_] = 10; //换行
  ++buffer_len_;

  if(is_out_buffer_) [[unlikely]] { //不需要打印头
    Log::output_((reinterpret_cast<char*>(this))+base_len_,buffer_len_);
  }else{
    Log::output_(this,base_len_ + buffer_len_);
  }
  buffer_len_ = 0;
  return *this;
};

Logstream& Logstream::operator<<(bool v){
  Append((v?"1":"0"), 1);
  return *this;
}
Logstream& Logstream::operator<<(short v){
  *this << static_cast<int>(v);
  return *this;
};
Logstream& Logstream::operator<<(unsigned short v){
  *this << static_cast<unsigned int>(v);
  return *this;
};
Logstream& Logstream::operator<<(int v){
  Format_integer(v);
  return *this;
};
Logstream& Logstream::operator<<(unsigned int v){
  Format_integer(v);
  return *this;
};
Logstream& Logstream::operator<<(long v){
  Format_integer(v);
  return *this;
};
Logstream& Logstream::operator<<(unsigned long v){
  Format_integer(v);
  return *this;
};
Logstream& Logstream::operator<<(long long v){
  Format_integer(v);
  return *this;
};
Logstream& Logstream::operator<<(unsigned long long v){
  Format_integer(v);
  return *this;
};
Logstream& Logstream::operator<<(const void* v){
  uint64_t p = reinterpret_cast<uint64_t>(v);
  Is_out_buffer(_C::SET_LOG_FMT_MAX_LEN);
  char* buf = data_buffer + buffer_len_;
  buf[0] = '0';
  buf[1] = 'x';
  buffer_len_ += 2;
  buffer_len_ += detail::ConvertHex(buf+2,p);
  return *this;
};
Logstream& Logstream::operator<<(float v){
  *this << static_cast<double>(v);
  return *this;
};
Logstream& Logstream::operator<<(double v){
  Is_out_buffer(_C::SET_LOG_FMT_MAX_LEN);
  buffer_len_ += snprintf(data_buffer+buffer_len_,_C::SET_LOG_FMT_MAX_LEN, "%.12g", v);
  return *this;
};
Logstream& Logstream::operator<<(char v){
  Append(&v, 1);
  return *this;
}
Logstream& Logstream::operator<<(const char* str){
  if (str){
    Append(str,strlen(str));
  }
  else{
    Append("(null)", 6);
  }
  return *this;
}
Logstream& Logstream::operator<<(const unsigned char* str){
  return operator<<(reinterpret_cast<const char*>(str));
}
Logstream& Logstream::operator<<(const std::string& v){
  Append(v.c_str(), v.size());
  return *this;
}
Logstream& Logstream::operator<<(const timeval& v){
  *this << "sec:" << v.tv_sec << "usec:" << v.tv_usec;
  return *this;
}

} // namespace net_tools::base